﻿#if MONO_CECIL
#else
#define _NET_REFLECTOR
#endif

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Data.EntityClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Resources;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Input;
using CallGraphExtractor;
using Model;
using ModelInitializer;
using Reflector.CodeModel;
using XmlDBAdapter;

namespace Analyzer.ViewModel
{
    public class MainWindowViewModel : ViewModelBase, IDataErrorInfo
    {
        #region Nested Types

        private delegate void CallGraphExtractionSubresultHandler(SubresultEventArgs<CallGraphEdgeCollection> e);
        private delegate void GetAssembliesSubresultHandler(SubresultEventArgs<IAssembly> e);
        private delegate void GetModulesSubresultHandler(SubresultEventArgs<IModule> e);
        private delegate void GetNamespacesSubresultHandler(SubresultEventArgs<string> e);
        private delegate void GetTypesSubresultHandler(SubresultEventArgs<ExtendedType> e);
        private delegate void GetMembersSubresultHandler(SubresultEventArgs<ExtendedMemberReference> e);

        #endregion Nested Types

        #region Fields

        private static readonly string sInitializedModelFileName = "InitializedModel";

        private BackgroundWorker mAnalysisWorker;
        private Extractor mExtractor;
        private CallGraphExtractionSubresultHandler mCallGraphExtractionSubresultHandler;
        private GetAssembliesSubresultHandler mGetAssembliesSubresultHandler;
        private GetModulesSubresultHandler mGetModulesSubresultHandler;
        private GetNamespacesSubresultHandler mGetNamespacesSubresultHandler;
        private GetTypesSubresultHandler mGetTypesSubresultHandler;
        private GetMembersSubresultHandler mGetMembersSubresultHandler;

        #region Syncronization

        #region Assemblies before Modules
        /// <summary>
        /// Syncronization object used to block extraction of module nodes until last assembly nodes are stored
        /// </summary>
        private ManualResetEvent mExtractCallGraphModuleNodesAsyncBlocker1 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of module nodes until Extractor.GetAssembliesDone event araised
        /// </summary>
        private ManualResetEvent mExtractCallGraphModuleNodesAsyncBlocker2 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of module nodes until all assembly-storing threads are done
        /// </summary>
        private ManualResetEvent mExtractCallGraphModuleNodesAsyncBlocker3 = new ManualResetEvent(false);
        private object mNumberOfThreadsStoringAssembliesSyncObject = new object();
        private int pNumberOfThreadsStoringAssemblies = 0;
        private int NumberOfThreadsStoringAssemblies
        {
            get
            {
                lock (mNumberOfThreadsStoringAssembliesSyncObject)
                    return pNumberOfThreadsStoringAssemblies;
            }
            set
            {
                lock (mNumberOfThreadsStoringAssembliesSyncObject)
                {
                    if (value != pNumberOfThreadsStoringAssemblies)
                        pNumberOfThreadsStoringAssemblies = value;
                    if (pNumberOfThreadsStoringAssemblies == 0)
                        mExtractCallGraphModuleNodesAsyncBlocker3.Set();
                }
            }
        }
        #endregion Assemblies before Modules

        #region Modules before Types
        /// <summary>
        /// Syncronization object used to block extraction of type nodes until last module nodes are stored
        /// </summary>
        private ManualResetEvent mExtractCallGraphTypeNodesAsyncBlockerByModules1 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of type nodes until Extractor.GetModulessDone event araised
        /// </summary>
        private ManualResetEvent mExtractCallGraphTypeNodesAsyncBlockerByModules2 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of type nodes until all modules-storing threads are done
        /// </summary>
        private ManualResetEvent mExtractCallGraphTypeNodesAsyncBlockerByModules3 = new ManualResetEvent(false);
        private object mNumberOfThreadsStoringModulesSyncObject = new object();
        private int pNumberOfThreadsStoringModules = 0;
        private int NumberOfThreadsStoringModules
        {
            get
            {
                lock (mNumberOfThreadsStoringModulesSyncObject)
                    return pNumberOfThreadsStoringModules;
            }
            set
            {
                lock (mNumberOfThreadsStoringModulesSyncObject)
                {
                    if (value != pNumberOfThreadsStoringModules)
                        pNumberOfThreadsStoringModules = value;
                    if (pNumberOfThreadsStoringModules == 0)
                        mExtractCallGraphTypeNodesAsyncBlockerByModules3.Set();
                }
            }
        }
        #endregion Modules before Types

        #region Namespaces before Types
        /// <summary>
        /// Syncronization object used to block extraction of type nodes until last namespace nodes are stored
        /// </summary>
        private ManualResetEvent mExtractCallGraphTypeNodesAsyncBlockerByNamespaces1 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of type nodes until Extractor.GetNamespacesDone event araised
        /// </summary>
        private ManualResetEvent mExtractCallGraphTypeNodesAsyncBlockerByNamespaces2 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of type nodes until all namespace-storing threads are done
        /// </summary>
        private ManualResetEvent mExtractCallGraphTypeNodesAsyncBlockerByNamespaces3 = new ManualResetEvent(false);
        private object mNumberOfThreadsStoringNamespacesSyncObject = new object();
        private int pNumberOfThreadsStoringNamespaces = 0;
        private int NumberOfThreadsStoringNamespaces
        {
            get
            {
                lock (mNumberOfThreadsStoringNamespacesSyncObject)
                    return pNumberOfThreadsStoringNamespaces;
            }
            set
            {
                lock (mNumberOfThreadsStoringNamespacesSyncObject)
                {
                    if (value != pNumberOfThreadsStoringNamespaces)
                        pNumberOfThreadsStoringNamespaces = value;
                    if (pNumberOfThreadsStoringNamespaces == 0)
                        mExtractCallGraphTypeNodesAsyncBlockerByNamespaces3.Set();
                }
            }
        }
        #endregion Namespaces before Types

        #region Types before Members
        /// <summary>
        /// Syncronization object used to block extraction of member nodes until last type nodes are stored
        /// </summary>
        private ManualResetEvent mExtractCallGraphMemberNodesAsyncBlocker1 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of member nodes until Extractor.GetTypesDone event araised
        /// </summary>
        private ManualResetEvent mExtractCallGraphMemberNodesAsyncBlocker2 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of member nodes until all type-storing threads are done
        /// </summary>
        private ManualResetEvent mExtractCallGraphMemberNodesAsyncBlocker3 = new ManualResetEvent(false);
        private object mNumberOfThreadsStoringTypesSyncObject = new object();
        private int pNumberOfThreadsStoringTypes = 0;
        private int NumberOfThreadsStoringTypes
        {
            get
            {
                lock (mNumberOfThreadsStoringTypesSyncObject)
                    return pNumberOfThreadsStoringTypes;
            }
            set
            {
                lock (mNumberOfThreadsStoringTypesSyncObject)
                {
                    if (value != pNumberOfThreadsStoringTypes)
                        pNumberOfThreadsStoringTypes = value;
                    if (pNumberOfThreadsStoringTypes == 0)
                        mExtractCallGraphMemberNodesAsyncBlocker3.Set();
                }
            }
        }
        #endregion Types before Members

        #region Members before Edges
        /// <summary>
        /// Syncronization object used to block extraction of call graph edges until last member nodes are stored
        /// </summary>
        private ManualResetEvent mExtractCallGraphBlocker1 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of callgraph edges until Extractor.GetMembersDone event araised
        /// </summary>
        private ManualResetEvent mExtractCallGraphBlocker2 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block extraction of callgraph edges until all member-storing threads are done
        /// </summary>
        private ManualResetEvent mExtractCallGraphBlocker3 = new ManualResetEvent(false);
        private object mNumberOfThreadsStoringMembersSyncObject = new object();
        private int pNumberOfThreadsStoringMembers = 0;
        private int NumberOfThreadsStoringMembers
        {
            get
            {
                lock (mNumberOfThreadsStoringMembersSyncObject)
                    return pNumberOfThreadsStoringMembers;
            }
            set
            {
                lock (mNumberOfThreadsStoringMembersSyncObject)
                {
                    if (value != pNumberOfThreadsStoringMembers)
                        pNumberOfThreadsStoringMembers = value;
                    if (pNumberOfThreadsStoringMembers == 0)
                        mExtractCallGraphBlocker3.Set();
                }
            }
        }
        #endregion Members before Edges

        /// <summary>
        /// Syncronization object used to block parsing of the FxCop report until last call graph edges are stored
        /// </summary>
        private ManualResetEvent mParseFxCopReportToDBBlocker1 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block parsing of the FxCop report until Extractor.ExtractionDone event araised
        /// </summary>
        private ManualResetEvent mParseFxCopReportToDBBlocker2 = new ManualResetEvent(false);
        /// <summary>
        /// Syncronization object used to block parsing of the FxCop report until all callgraph-edge-storing threads are done
        /// </summary>
        private ManualResetEvent mParseFxCopReportToDBBlocker3 = new ManualResetEvent(false);
        private object mNumberOfThreadsStoringCallGraphEdgesSyncObject = new object();
        private int pNumberOfThreadsStoringCallGraphEdges = 0;
        private int NumberOfThreadsStoringCallGraphEdges
        {
            get
            {
                lock (mNumberOfThreadsStoringCallGraphEdgesSyncObject)
                    return pNumberOfThreadsStoringCallGraphEdges;
            }
            set
            {
                lock (mNumberOfThreadsStoringCallGraphEdgesSyncObject)
                {
                    if (value != pNumberOfThreadsStoringCallGraphEdges)
                        pNumberOfThreadsStoringCallGraphEdges = value;
                    if (pNumberOfThreadsStoringCallGraphEdges == 0)
                        mParseFxCopReportToDBBlocker3.Set();
                }
            }
        }
        #endregion Syncronization

        private HashSet<ExtendedType> mUnresolvedTypes = new HashSet<ExtendedType>();

        #endregion Fields

        #region Lifecycle

        public MainWindowViewModel()
        {
            mExtractor = new Extractor();
            this.Files = new ObservableCollection<AssemblyViewModel>();
            this.IsInitializing = true;
            this.IsInProgress = false;
            this.Progress = 0;
            this.IsProgressIndeterminate = false;
            this.Output = new ObservableCollection<string>();
            this.FxCop10Path =
                new Uri(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
                    + "\\Microsoft FxCop 10.0\\FxCopCmd.exe");
            this.FxCopRulesPath = new Uri(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
                    + "\\Microsoft FxCop 10.0\\Rules");
            string visualStudioRulesPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
                    + "\\Microsoft Visual Studio 10.0\\Team Tools\\Static Analysis Tools\\FxCop\\Rules";
            if (Directory.Exists(visualStudioRulesPath) == true)
                this.VisualStudioRulesPath = new Uri(visualStudioRulesPath);
            else
                this.VisualStudioRulesPath = null;
            //ISO9126toFxCop_ISO9126.csv
            //ISO9126toFxCop_Mapping.csv

            mExtractor.GetAssembliesSubresultExtracted
                += new EventHandler<SubresultEventArgs<IAssembly>>(mExtractor_GetAssembliesSubresultExtracted);
            mExtractor.GetAssembliesProgressChanged
                += new EventHandler<ProgressChangedEventArgs>(mExtractor_GetAssembliesProgressChanged);
            mExtractor.GetAssembliesDone +=
                new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetAssembliesDone);
            mGetAssembliesSubresultHandler = new GetAssembliesSubresultHandler(StoreGetAssembliesSubresult);

            mExtractor.GetModulesSubresultExtracted +=
                new EventHandler<SubresultEventArgs<IModule>>(mExtractor_GetModulesSubresultExtracted);
            mExtractor.GetModulesProgressChanged +=
                new EventHandler<ProgressChangedEventArgs>(mExtractor_GetModulesProgressChanged);
            mExtractor.GetModulesDone +=
                new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetModulesDone);
            mGetModulesSubresultHandler = new GetModulesSubresultHandler(StoreGetModulesSubresult);

            mExtractor.GetNamespacesSubresultExtracted +=
                new EventHandler<SubresultEventArgs<string>>(mExtractor_GetNamespacesSubresultExtracted);
            mExtractor.GetNamespacesProgressChanged
                += new EventHandler<ProgressChangedEventArgs>(mExtractor_GetNamespacesProgressChanged);
            mExtractor.GetNamespacesDone
                += new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetNamespacesDone);
            mGetNamespacesSubresultHandler = new GetNamespacesSubresultHandler(StoreGetNamespacesSubresult);

            mExtractor.GetTypesSubresultExtracted +=
                new EventHandler<SubresultEventArgs<ExtendedType>>(mExtractor_GetTypesSubresultExtracted);
            mExtractor.GetTypesProgressChanged +=
                new EventHandler<ProgressChangedEventArgs>(mExtractor_GetTypesProgressChanged);
            mExtractor.GetTypesDone +=
                new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetTypesDone);
            mGetTypesSubresultHandler = new GetTypesSubresultHandler(StoreGetTypesSubresult);

            mExtractor.GetMembersSubresultExtracted +=
                new EventHandler<SubresultEventArgs<ExtendedMemberReference>>(mExtractor_GetMembersSubresultExtracted);
            mExtractor.GetMembersProgressChanged +=
                new EventHandler<ProgressChangedEventArgs>(mExtractor_GetMembersProgressChanged);
            mExtractor.GetMembersDone +=
                new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_GetMembersDone);
            mGetMembersSubresultHandler = new GetMembersSubresultHandler(StoreGetMembersSubresult);

            mExtractor.ExtractionSubresultExtracted +=
                new EventHandler<SubresultEventArgs<CallGraphEdgeCollection>>(mExtractor_SubresultExtracted);
            mExtractor.ExtractionProgressChanged +=
                new EventHandler<ProgressChangedEventArgs>(mExtractor_ProgressChanged);
            mExtractor.ExtractionDone += new EventHandler<RunWorkerCompletedEventArgs>(mExtractor_ExtractionDone);
            mCallGraphExtractionSubresultHandler =
                new CallGraphExtractionSubresultHandler(StoreCallGraphExtractionSubresult);

            mExtractor.Informating += new EventHandler<InformationEventArgs>(mExtractor_Informating);
            mExtractor.StateChanged += new EventHandler<InformationEventArgs>(mExtractor_StateChanged);

            #region DesignTimeData
            if (DesignerProperties.GetIsInDesignMode(new System.Windows.DependencyObject()) == true)
            {
                string codeBase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
                UriBuilder uri = new UriBuilder(codeBase);
                string path = Uri.UnescapeDataString(uri.Path);
                string directoryPath = Path.GetDirectoryName(path);

                this.Files.Add(
                    new AssemblyViewModel()
                    {
                        FilePath = directoryPath + "\\executableFile.exe"
                    });
                this.Files.Add(
                    new AssemblyViewModel()
                    {
                        FilePath = directoryPath + "\\libraryFile.dll",
                        IsSelected = true
                    });
                this.Files.Add(
                    new AssemblyViewModel()
                    {
                        FilePath = directoryPath + "\\otherFile.stg"
                    });

                this.IsInProgress = true;
                this.Progress = 50;

                for (int i = 0; i < 5; i++)
                {
                    this.Output.Add("Output" + i.ToString());
                }
            }
            #endregion DesignTimeData
#if DEBUG
            this.CopyCallGraphModel = true;
#endif
        }

        #endregion Lifecycle

        #region Properties

        #region Presentation

        private bool pMustRewriteInitializedModel;
        public bool MustRewriteInitializedModel
        {
            get { return pMustRewriteInitializedModel; }
            set
            {
                if (value != pMustRewriteInitializedModel)
                {
                    pMustRewriteInitializedModel = value;
                    OnPropertyChanged("MustRewriteInitializedModel");
                }
            }
        }

        private bool pOnlyRewriteFxCopReport;
        public bool OnlyRewriteFxCopReport
        {
            get { return pOnlyRewriteFxCopReport; }
            set
            {
                if (value != pOnlyRewriteFxCopReport)
                {
                    pOnlyRewriteFxCopReport = value;
                    OnPropertyChanged("OnlyRewriteFxCopReport");
                }
            }
        }

        private string pProjectName;
        public string ProjectName
        {
            get { return pProjectName; }
            set
            {
                if (value.Equals(pProjectName) == false)
                {
                    pProjectName = value;
                    OnPropertyChanged("ProjectName");
                    Trace.TraceInformation("Project name set to {0}", pProjectName);
                }
            }
        }

        /// <summary>
        /// Gets the collection of files, which will be analyzed.
        /// </summary>
        public ObservableCollection<AssemblyViewModel> Files { get; private set; }

        /// <summary>
        /// Gets a value indicating, that analysis is not yet occured, and the
        /// viewmodel is in a state where parameters should be set.
        /// </summary>
        private bool pIsInitializing;
        public bool IsInitializing
        {
            get { return pIsInitializing; }
            private set
            {
                if (value != pIsInitializing)
                {
                    pIsInitializing = value;
                    OnPropertyChanged("IsInitializing");
                }
            }
        }

        /// <summary>
        /// Gets a value indicating that analysis (or a corresponding activity) is in progress.
        /// </summary>
        private bool pIsInProgress;
        public bool IsInProgress
        {
            get { return pIsInProgress; }
            private set
            {
                if (value != pIsInProgress)
                {
                    pIsInProgress = value;
                    OnPropertyChanged("IsInProgress");
                }
            }
        }

        /// <summary>
        /// Gets, or sets the path to FxCopCmd.exe of FxCop 10.0
        /// </summary>
        private Uri pFxCop10Path;
        public Uri FxCop10Path
        {
            get { return pFxCop10Path; }
            set
            {
                if (value != pFxCop10Path)
                {
                    pFxCop10Path = value;
                    OnPropertyChanged("FxCop10Path");
                }
            }
        }

        /// <summary>
        /// Gets, or sets the path to the folder that contains the FxCop 10.0 rules.
        /// </summary>
        private Uri pFxCopRulesPath;
        public Uri FxCopRulesPath
        {
            get { return pFxCopRulesPath; }
            set
            {
                if (value != pFxCopRulesPath)
                {
                    pFxCopRulesPath = value;
                    OnPropertyChanged("FxCopRulesPath");
                }
            }
        }

        /// <summary>
        /// Gets, or sets the path to the folder that contains the FxCop 10.0 rules that are supported
        /// only in VS2010 Premium/Ultimate.
        /// </summary>
        private Uri pVisualStudioRulesPath;
        public Uri VisualStudioRulesPath
        {
            get { return pVisualStudioRulesPath; }
            set
            {
                if (value != pVisualStudioRulesPath)
                {
                    pVisualStudioRulesPath = value;
                    OnPropertyChanged("VisualStudioRulesPath");
                }
            }
        }

        /// <summary>
        /// Gets a value indicating the executability of <see cref="AnalyzeCommand"/>.
        /// </summary>
        public bool CanAnalyze
        {
            get { return this.AnalyzeCommand.CanExecute(null); }
        }

        private int pProgress;
        public int Progress
        {
            get { return pProgress; }
            private set
            {
                if (value != pProgress)
                {
                    pProgress = value;
                    OnPropertyChanged("Progress");
                }
            }
        }

        private bool pIsProgressIndeterminate;
        public bool IsProgressIndeterminate
        {
            get { return pIsProgressIndeterminate; }
            private set
            {
                if (value != pIsProgressIndeterminate)
                {
                    pIsProgressIndeterminate = value;
                    OnPropertyChanged("IsProgressIndeterminate");
                }
            }
        }

        public ObservableCollection<string> Output { get; private set; }

        private bool pHasError;
        public bool HasError
        {
            get { return pHasError; }
            private set
            {
                if (value != pHasError)
                {
                    pHasError = value;
                    OnPropertyChanged("HasError");
                }
            }
        }

        private string pState;
        public string State
        {
            get { return pState; }
            set
            {
                if (pState != value)
                {
                    pState = value;
                    OnPropertyChanged("State");
                }
            }
        }

        public static string TempDirectoryPath
        {
            get
            {
                return Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
                    + "\\Analyzer\\temp\\";//System.Reflection.Assembly.GetExecutingAssembly().Location;
                //string dir = Path.GetDirectoryName(path);
            }
        }

        /// <summary>
        /// Gets the path ending with the filename where FxCop will save its output.
        /// </summary>
        public string FxCopOutputPath
        {
            get
            {
                string path = TempDirectoryPath;
                if (Directory.Exists(path) == false)
                    Directory.CreateDirectory(path);

                string value = path
                    + (this.ProjectName.Equals("") == true || this.ProjectName == null
                    ? "noNameProjectAnalysisReport.xml"
                    : this.ProjectName + "AnalysisReport.xml");
                return value;
            }
        }

        #endregion Presentation

        private ActualEntities pContext;
        private ActualEntities Context
        {
            get { return pContext; }
            set
            {
                if (value != pContext)
                    pContext = value;
            }
        }

        private Uri ModelPath { get; set; }

        private bool CopyCallGraphModel { get; set; }

        private static ResourceManager pRM;
        public static ResourceManager RM
        {
            get
            {
                if (pRM == null)
                    pRM = new ResourceManager("Resources", System.Reflection.Assembly.GetExecutingAssembly());
                return pRM;
            }
        }

        #endregion Properties

        #region Commands

        private RelayCommand pAddFilesCommand;
        public ICommand AddFilesCommand
        {
            get
            {
                if (pAddFilesCommand == null)
                    pAddFilesCommand =
                        new RelayCommand(
                            param =>
                            {
                                Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
                                ofd.AddExtension = true;
                                ofd.DefaultExt = ".ea";
                                ofd.Filter = "Végrehajtható|*.exe|Osztálykönyvtár|*.dll|Minden fájl|*.*";
                                ofd.FilterIndex = 0;
                                ofd.Title = "Fájlok tallózása";
                                ofd.ValidateNames = true;
                                ofd.Multiselect = true;
                                ofd.CheckFileExists = true;
                                ofd.CheckPathExists = true;
                                bool? success = ofd.ShowDialog();
                                if (success.HasValue && success.Value == true)
                                {
                                    foreach (var item in ofd.FileNames)
                                    {
                                        this.Files.Add(
                                            new AssemblyViewModel()
                                            {
                                                FilePath = item,
                                                IsSelected = false
                                            });
                                    }
                                }
                            },
                            param => true);
                return pAddFilesCommand;
            }
        }

        private RelayCommand pRemoveFilesCommand;
        public ICommand RemoveFilesCommand
        {
            get
            {
                if (pRemoveFilesCommand == null)
                    pRemoveFilesCommand =
                        new RelayCommand(
                            param =>
                            {
                                List<AssemblyViewModel> toDelete = new List<AssemblyViewModel>();
                                foreach (var item in this.Files)
                                {
                                    if (item.IsSelected == true)
                                        toDelete.Add(item);
                                }
                                foreach (var item in toDelete)
                                {
                                    this.Files.Remove(item);
                                }
                            },
                            param => this.Files.Count > 0);
                return pRemoveFilesCommand;
            }
        }

        private RelayCommand pAnalyzeCommand;
        public ICommand AnalyzeCommand
        {
            get
            {
                if (pAnalyzeCommand == null)
                    pAnalyzeCommand =
                        new RelayCommand(
                            param =>
                            {
                                mAnalysisWorker = new BackgroundWorker();
                                mAnalysisWorker.WorkerReportsProgress = true;
                                mAnalysisWorker.WorkerSupportsCancellation = true;
                                mAnalysisWorker.DoWork += new DoWorkEventHandler(mAnalysisWorker_DoWork);
                                mAnalysisWorker.ProgressChanged +=
                                    new ProgressChangedEventHandler(mAnalysisWorker_ProgressChanged);
                                mAnalysisWorker.RunWorkerCompleted +=
                                    new RunWorkerCompletedEventHandler(mAnalysisWorker_RunWorkerCompleted);
                                mAnalysisWorker.RunWorkerAsync(this.Files.ToList());
                                this.IsInitializing = false;
                                this.IsInProgress = true;
                            },
                            param => this["FxCop10Path"] == null
                                && this["FxCopRulesPath"] == null
                                && this.IsInitializing == true
                                && this.IsInProgress == false
                                && this.Files.Count > 0);
                return pAnalyzeCommand;
            }
        }

        private RelayCommand pBrowseFxCopCmdCommand;
        public ICommand BrowseFxCopCmdCommand
        {
            get
            {
                if (pBrowseFxCopCmdCommand == null)
                    pBrowseFxCopCmdCommand =
                        new RelayCommand(
                            param =>
                            {
                                Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
                                ofd.AddExtension = true;
                                ofd.DefaultExt = ".ea";
                                ofd.Filter = "Végrehajtható|*.exe";
                                ofd.FilterIndex = 0;
                                ofd.Title = "FxCopCmd.exe tallózása";
                                ofd.ValidateNames = true;
                                ofd.Multiselect = false;
                                ofd.CheckFileExists = true;
                                ofd.CheckPathExists = true;
                                ofd.InitialDirectory =
                                    Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                                bool? success = ofd.ShowDialog();
                                if (success.HasValue && success.Value == true)
                                {
                                    foreach (var item in ofd.FileNames)
                                    {
                                        this.Files.Add(
                                            new AssemblyViewModel()
                                            {
                                                FilePath = item,
                                                IsSelected = false
                                            });
                                    }
                                }
                            },
                            param => true);
                return pBrowseFxCopCmdCommand;
            }
        }

        private RelayCommand pBrowseFxCopRulesCommand;
        public ICommand BrowseFxCopRulesCommand
        {
            get
            {
                if (pBrowseFxCopRulesCommand == null)
                    pBrowseFxCopRulesCommand =
                        new RelayCommand(
                            param =>
                            {
                                FolderBrowserDialog fbd = new FolderBrowserDialog();
                                fbd.ShowNewFolderButton = false;
                                fbd.Description = "FxCop 10.0 szabályok tallózása";
                                //fbd.InitialDirectory =
                                //    Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                                DialogResult result = fbd.ShowDialog();
                                bool? success;
                                switch (result)
                                {
                                    case DialogResult.Cancel:
                                        success = false;
                                        break;
                                    case DialogResult.OK:
                                        success = true;
                                        break;
                                    default:
                                        success = null;
                                        break;
                                }
                                if (success.HasValue && success.Value == true)
                                {
                                    this.FxCopRulesPath = new Uri(fbd.SelectedPath);
                                }
                            },
                            param => true);
                return pBrowseFxCopCmdCommand;
            }
        }

        private RelayCommand pBrowseVisualStudioRulesCommand;
        public ICommand BrowseVisualStudioRulesCommand
        {
            get
            {
                if (pBrowseVisualStudioRulesCommand == null)
                    pBrowseVisualStudioRulesCommand =
                        new RelayCommand(
                            param =>
                            {
                                FolderBrowserDialog fbd = new FolderBrowserDialog();
                                fbd.ShowNewFolderButton = false;
                                fbd.Description = "VS2010 Premium/Ultimate FxCop szabályok tallózása";
                                //fbd.InitialDirectory =
                                //    Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                                DialogResult result = fbd.ShowDialog();
                                bool? success;
                                switch (result)
                                {
                                    case DialogResult.Cancel:
                                        success = false;
                                        break;
                                    case DialogResult.OK:
                                        success = true;
                                        break;
                                    default:
                                        success = null;
                                        break;
                                }
                                if (success.HasValue && success.Value == true)
                                {
                                    this.VisualStudioRulesPath = new Uri(fbd.SelectedPath);
                                }
                            },
                            param => true);
                return pBrowseFxCopCmdCommand;
            }
        }

        #endregion Commands

        #region Methods

        /// <summary>
        /// Gets the arguments which will be passed to FxCopCmd.
        /// </summary>
        /// <returns>The arguments</returns>
        public string GetFxCopArguments()
        {
            string value = "/o:\"" + this.FxCopOutputPath + "\" /fo";
            foreach (var item in this.Files)
            {
                value += " /f:\"" + item.FilePath + "\"";
            }
            if (this.VisualStudioRulesPath != null
                && Directory.Exists(this.VisualStudioRulesPath.LocalPath) == true)
                value += " /r:\"" + this.VisualStudioRulesPath.LocalPath + "\"";
            else
                value += " /r:\"" + this.FxCopRulesPath.LocalPath + "\"";
            return value;
        }

        private bool CopyFiles(List<AssemblyViewModel> files)
        {
            this.Output.Add("Vizsgálandó fájlok másolása...");
            foreach (var file in files)
            {
                if (File.Exists(file.FileName) == false
                    || (File.Exists(file.FileName) == true
                        && File.GetLastWriteTime(file.FileName) != File.GetLastWriteTime(file.FilePath)))
                {
                    try
                    {
                        File.Copy(file.FilePath, file.FileName, overwrite: true);
                        file.DeleteIsNeeded = true;

                        if (file.HasProgramDatabase == true
                            && File.Exists(file.ProgramDatabaseFileName) == false
                            || (File.Exists(file.ProgramDatabaseFileName) == true
                                && File.GetLastWriteTime(file.ProgramDatabaseFileName) != File.GetLastWriteTime(file.ProgramDatabaseFilePath)))
                        {
                            File.Copy(file.ProgramDatabaseFilePath, file.ProgramDatabaseFileName, overwrite: true);
                            file.ProgramDatabaseDeleteIsNeeded = true;
                        }
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        MessageBox.Show(ex.Message
                            + " Futassa az alkalmazást rendszergazdaként, vagy oldja fel a fájl írásvédettségét!");
                        return false;
                    }
                    catch (IOException ex)
                    {
                        MessageBox.Show(ex.Message);
                        return false;
                    }

                }
            }
            this.Output.Add("kész");
            return true;
        }

        internal void DeleteFiles()
        {
            DeleteFiles(this.Files.ToList());
        }

        private void DeleteFiles(List<AssemblyViewModel> files)
        {
            this.Output.Add("Elemzett fájlmásolatok törlése...");
            foreach (var file in files)
            {
                if (File.Exists(file.FileName) == true
                    || (File.Exists(file.FileName) == true
                        && File.GetLastWriteTime(file.FileName) != File.GetLastWriteTime(file.FilePath)))
                {
                    try
                    {
                        if (file.DeleteIsNeeded == true)
                            File.Delete(file.FileName);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        MessageBox.Show(ex.Message
                            + " Futassa az alkalmazást rendszergazdaként, vagy oldja fel a fájl írásvédettségét!");
                    }

                    try
                    {
                        if (file.ProgramDatabaseDeleteIsNeeded == true)
                            File.Delete(file.ProgramDatabaseFileName);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        MessageBox.Show(ex.Message
                            + " Futassa az alkalmazást rendszergazdaként, vagy oldja fel a fájl írásvédettségét!");
                    }

                }
            }
            this.Output.Add("kész");
        }

        private bool CreateDB()
        {
            DispatchService.Dispatch(() => this.Output.Add("Új adatbázis létrehozása..."));
            this.IsProgressIndeterminate = true;
            string dbPath = null;
            string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Analyzer";
            if (Directory.Exists(appDataPath) == false) // Create Analyzer subdir in AppData if does not exists
                Directory.CreateDirectory(appDataPath);
            string newPathTemplate = appDataPath + "\\{0}.db3";
            string initializedModelPath = newPathTemplate.Replace("{0}", sInitializedModelFileName);
            string newModelPath = newPathTemplate.Replace("{0}", this.ProjectName);
            this.IsProgressIndeterminate = false;
            // If database file already exists, ask about overwrite
            if (File.Exists(newModelPath) == true
                 && (MessageBox.Show(
                        "A fájl " + this.ProjectName + ".db3 már létezik. Felülírjam?",
                        "A fájl már létezik!",
                        MessageBoxButtons.YesNo,
                        MessageBoxIcon.Question) != DialogResult.Yes))
                return false;
            this.IsProgressIndeterminate = true;

            this.ModelPath = new Uri(newModelPath);

            string modelPath = @"Resources\\Model.db3";//RM.GetString("ModelPath");//, CultureInfo.InvariantCulture);
            // If initialized database does not exist,
            //    or has written earlier than reference database in Resources (reference db has changed)
            //    or must rewrite
            if ((File.Exists(initializedModelPath) == false
                || File.GetLastWriteTime(initializedModelPath) < File.GetLastWriteTime(modelPath)
                || this.MustRewriteInitializedModel == true)
                && this.OnlyRewriteFxCopReport == false)
            {
                // Then copy the reference database and initialize
                if (File.GetLastWriteTime(@"..\\..\\Model\\Model\\3rdparty\\Model.db3")
                    > File.GetLastWriteTime(@"Resources\\Model.db3"))
                    throw new InvalidOperationException(@"Resources\\Model.db3" + " is out of date!");//TODO TEST: elvileg ez már nem történhet meg
                File.Copy(modelPath, initializedModelPath, overwrite: true);//TODO: overwrite param

                EntityConnectionStringBuilder builder = new EntityConnectionStringBuilder();
                builder.Metadata = "res://*/ActualModel.csdl|res://*/ActualModel.ssdl|res://*/ActualModel.msl";
                builder.Provider = "System.Data.SQLite";
                builder.ProviderConnectionString = "data source=\"" + initializedModelPath + "\"";
                Initializer init = new Initializer();
                init.ProgressChanged += new EventHandler<ProgressChangedEventArgs>(init_ProgressChanged);
                init.Initialize(new ActualEntities(builder.ConnectionString),
                    Properties.Resources.ISO9126toFxCop_ISO9126,
                    Properties.Resources.ISO9126toFxCop_Mapping,
                    Properties.Resources.ISO9126toFxCop_EffectMatrix,
                    this.FxCopRulesPath,
                    this.VisualStudioRulesPath);
                init.ProgressChanged -= init_ProgressChanged;
            }// The whole purpose of this block is to avoid everytime-initialization of the database
            dbPath = newPathTemplate;

            if (this.OnlyRewriteFxCopReport == false)
                // Copy and rename initialized database to target directory
                File.Copy(initializedModelPath, newModelPath, overwrite: true);
            this.Context = GetContext(newModelPath);

            if (this.OnlyRewriteFxCopReport)
            {
                Debug.Assert(this.Context.QualityCharacteristics.Count() > 0);
                Debug.Assert(this.Context.Categories.Count() > 0);
                Debug.Assert(this.Context.Category_Subcharacteristic.Count() > 0);
                Debug.Assert(this.Context.Rules.Count() > 0);
                Debug.Assert(this.Context.Rule_FxCopRule.Count() > 0);
                Debug.Assert(this.Context.Mappings.Count() > 0);
            }
            return true;
        }

        private ActualEntities GetContext(string modelPath)
        {
            EntityConnectionStringBuilder builder2 = new EntityConnectionStringBuilder();
            builder2.Metadata = "res://*/ActualModel.csdl|res://*/ActualModel.ssdl|res://*/ActualModel.msl";
            builder2.Provider = "System.Data.SQLite";
            builder2.ProviderConnectionString = "data source=\"" + modelPath + "\"";
            return new ActualEntities(builder2.ConnectionString);
        }

        /// <summary>
        /// DefaultCollaboration 4.0
        /// </summary>
        private void ExtractCallGraphAssemblyNodesAsync()
        {
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Asszemblik meghatározása..."));
            mExtractor.GetAssembliesAsync(new ManualResetEvent[] { });
        }

        /// <summary>
        /// DefaultCollaboration 4.1
        /// </summary>
        private void ExtractCallGraphModuleNodesAsync()
        {
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Modulok meghatározása..."));
            mExtractor.GetModulesAsync(
                new ManualResetEvent[]
                {
                    mExtractCallGraphModuleNodesAsyncBlocker1,
                    mExtractCallGraphModuleNodesAsyncBlocker2
                });
        }

        /// <summary>
        /// DefaultCollaboration 4.2
        /// </summary>
        private void ExtractCallGraphNamespaceNodesAsync()
        {
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Névterek kinyerése..."));
            mExtractor.GetNamespacesAsync(new ManualResetEvent[] { });
        }

        /// <summary>
        /// DefaultCollaboration 4.3
        /// </summary>
        private void ExtractCallGraphTypeNodesAsync()
        {
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Típusok kinyerése..."));
            mExtractor.GetTypesAsync(
                new ManualResetEvent[]
                {
                    mExtractCallGraphTypeNodesAsyncBlockerByModules1,
                    mExtractCallGraphTypeNodesAsyncBlockerByModules2,
                    mExtractCallGraphTypeNodesAsyncBlockerByNamespaces1,
                    mExtractCallGraphTypeNodesAsyncBlockerByNamespaces2
                });
        }

        /// <summary>
        /// DefaultCollaboration 4.4
        /// </summary>
        private void ResolveNestedTypeAssociations()
        {
            ActualEntities context = this.Context;
            lock (context)
                foreach (var item in mUnresolvedTypes)
                {
                    IModule iModule = item.Module;
                    ITypeDeclaration outerTd = null;
                    bool resolved = item.OuterType.TryGetTypeDeclaration(out outerTd);
                    ITypeDeclaration nestedTd = null;
                    resolved &= item.Type.TryGetTypeDeclaration(out nestedTd);
                    if (resolved == true)
                    {
                        Model.Type outerType = context.Types.Where(
                            t => t.Name.Equals(outerTd.Name) && t.NamespaceName.Equals(outerTd.Namespace)
                                   && t.ModuleName.Equals(iModule.Name)
                                   && t.ModuleAssemblyName.Equals(iModule.Assembly.Name)).First();
                        var nestedTypeQuery = context.Types.Where(
                            t => t.Name.Equals(nestedTd.Name) && t.NamespaceName.Equals(nestedTd.Namespace)
                                && t.ModuleName.Equals(iModule.Name)
                                && t.ModuleAssemblyName.Equals(iModule.Assembly.Name));
                        Model.Type nestedType;
                        Model.Namespace nestedNS;
                        if (nestedTypeQuery.Count() > 0)
                        {
                            nestedType = nestedTypeQuery.First();

                            nestedType.Outer_TypeName = outerType.Name;
                            nestedType.Outer_TypeNamespaceName = outerType.NamespaceName;
                            nestedType.Outer_TypeModuleName = outerType.ModuleName;
                            nestedType.Outer_TypeModuleAssemblyName = outerType.Outer_TypeModuleAssemblyName;
                            nestedType.OuterType = outerType;
                            outerType.NestedType.Add(nestedType);
                        }
                        else
                        {
                            CreateType(this.Context, item, nestedTd, outerType.Module, null,
                                outerType, out nestedType, out nestedNS);
                            this.Context.Types.AddObject(nestedType);
                            this.Context.Namespaces.AddObject(nestedNS);
                        }
                        context.SaveChanges();
                    }
#if DEBUG
                    else
                        MessageBox.Show(item.Type.ToString() + " nested type is not resolved!");
#endif
                }
        }

        /// <summary>
        /// DefaultCollaboration 4.5
        /// </summary>
        private void ExtractCallGraphMemberNodesAsync()
        {
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Tagok kinyerése..."));
            mExtractor.GetMembersAsync(
                new ManualResetEvent[]
                {
                    mExtractCallGraphMemberNodesAsyncBlocker1,
                    mExtractCallGraphMemberNodesAsyncBlocker2
                });
        }

        /// <summary>
        /// DefaultCollaboration 4.6
        /// </summary>
        private void ExtractCallGraph()
        {
            if (this.HasError == true)
                return;
            DispatchService.Dispatch(() => this.Output.Add("Hívások kinyerése..."));
            mExtractor.ExtractAsync(
                new ManualResetEvent[]
                {
                    mExtractCallGraphBlocker1,
                    mExtractCallGraphBlocker2
                });
        }

        /// <summary>
        /// DefaultCollaboration 7
        /// </summary>
        private void RunFxCopAnalysis()
        {
            if (this.HasError == true)
                return;

            this.State = "Starting FxCop analysis";
            if (this.CopyCallGraphModel == true)
            {
                File.Copy(this.ModelPath.LocalPath,
                    this.ModelPath.LocalPath.Replace("\\" + this.ProjectName + ".db3",
                        "\\" + this.ProjectName + "_CG.db3"),
                    overwrite: true);
            }

            using (Process p = new Process())
            {
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.FileName = this.FxCop10Path.LocalPath;

                p.StartInfo.Arguments = this.GetFxCopArguments();

                try
                {
                    p.Start();
                    StreamReader reader = p.StandardOutput;
                    StreamWriter writer = p.StandardInput;
                    StreamReader errorReader = p.StandardError;
                    writer.AutoFlush = true;
                    String rawOutput = reader.ReadToEnd();
                    string[] output =
                        rawOutput.Split(new string[] { Environment.NewLine },
                            StringSplitOptions.RemoveEmptyEntries);
                    DispatchService.Dispatch(() =>
                    {
                        foreach (var item in output)
                        {
                            this.Output.Add(item);
                        }
                    });
                    string error = errorReader.ReadToEnd();
                    if (error != null && error.Length != 0)
                        throw new AnalysisException(error);
                }
                catch (Win32Exception ex)
                {
                    System.Windows.MessageBox.Show(ex.Message);
                    this.HasError = true;
                }
                catch (AnalysisException ex)
                {
                    if (ex.Message.Contains("dataflowrules.dll") == false)
                    {
                        System.Windows.MessageBox.Show(ex.Message);
                        this.HasError = true;
                    }
                }
            }
        }

        #region Store to DB

        private void StoreGetAssembliesSubresult(SubresultEventArgs<IAssembly> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " assemblies extracted.");
            if (e.Subresult.Count == 0)
            {
                mExtractCallGraphModuleNodesAsyncBlocker1.Set();
                return;
            }

            this.NumberOfThreadsStoringAssemblies += 1;
#if STORE_DEBUG
            Debug.WriteLine("Duplicates:");
#endif
            int i = 0;
            lock (this.Context)
            //using (ActualEntities context = GetContext(this.ModelPath.LocalPath))//this.Context;//new Model.ActualEntities();
            {
                var context = this.Context;
                var query = context.Projects.Where(p => p.Name.Equals(this.ProjectName));
                if (query.Count() == 0)
                {
                    context.Projects.AddObject(
                        new Project()
                        {
                            Name = this.ProjectName
                        });
                    context.SaveChanges();
                }
                Debug.WriteLineIf(query.Count() != 1, this.ProjectName
                    + " nevű projektből nem pontosan 1 található!");
                Project project = query.First();
                foreach (var item in e.Subresult)
                {
                    this.State = item.Name + " asszembli tárolása";
                    if (context.Assemblies.Where(a => a.Name.Equals(item.Name)).Count() == 0)
                    {
                        Assembly a =
                            new Assembly()
                            {
                                Name = item.Name,
                                ProjectId = project.Id,
                                Project = project
                            };
                        context.Assemblies.AddObject(a);
                        project.Assemblies.Add(a);
                        try
                        {
                            context.SaveChanges();
                        }
                        catch (UpdateException ex)
                        {
                            if (context.Assemblies.Where(aa => aa.Name.Equals(item.Name)).Count() == 0)
                                Trace.TraceError("Could not save " + a.Name + " assembly due to a constraint violation!");
                            else
                            {
                                context.Detach(a);
                                context.SaveChanges();
                            }
                        }
                        i++;
                    }
#if STORE_DEBUG
                    else
                        Debug.Write(item.Name + " ");
#endif
                }
            }
            //}
            Debug.WriteLine(i.ToString() + " assemblies stored.");
            this.NumberOfThreadsStoringAssemblies -= 1;
        }

        private void StoreGetModulesSubresult(SubresultEventArgs<IModule> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " modules extracted.");
            if (e.Subresult.Count == 0)
            {
                mExtractCallGraphTypeNodesAsyncBlockerByModules1.Set();
                return;
            }

            this.NumberOfThreadsStoringModules += 1;
            mExtractCallGraphModuleNodesAsyncBlocker3.WaitOne();
#if STORE_DEBUG
            Debug.WriteLine("Duplicates:");
#endif
            int i = 0;
            lock (this.Context)
            //using (ActualEntities context = GetContext(this.ModelPath.LocalPath))//this.Context;//new Model.ActualEntities();
            {
                var context = this.Context;
                foreach (var item in e.Subresult)
                {
                    this.State = item.Name + " modul tárolása";
#if _NET_REFLECTOR
                    string assemblyName =
                        item.Assembly.Name.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
#elif MONO_CECIL
                    string assemblyName = item.Assembly.Name;
#endif
                    var query = context.Assemblies.Where(
                        a => a.Project.Name.Equals(this.ProjectName) && a.Name.Equals(assemblyName));
                    Debug.WriteLineIf(query.Count() != 1,
                        this.ProjectName + " nevű projektben "
                        + assemblyName + " asszembliből nem pontosan 1 található!");
                    if (context.Modules.Where(
                            m => m.AssemblyName.Equals(assemblyName)
                                && m.Name.Equals(item.Name)).Count() == 0)
                    {
                        Assembly assembly = query.First();
                        Module m =
                            new Module()
                            {
                                Name = item.Name,
                                Assembly = assembly,
                                AssemblyName = assembly.Name
                            };
                        context.Modules.AddObject(m);
                        assembly.Modules.Add(m);
                        try
                        {
                            context.SaveChanges();
                        }
                        catch (UpdateException ex)
                        {
                            if (context.Modules.Where(
                                    mm => mm.AssemblyName.Equals(assemblyName)
                                        && mm.Name.Equals(item.Name)).Count() == 0)
                                Trace.TraceError("Could not save " + m.Name + " containerModule due to a constraint violation!");
                            else
                            {
                                context.Detach(m);
                                context.SaveChanges();
                            }
                        }
                        i++;
                    }
#if STORE_DEBUG
                    else
                        Debug.Write(item.Name + " ");
#endif
                }
            }
            Debug.WriteLine(i.ToString() + " modules stored.");
            this.NumberOfThreadsStoringModules -= 1;
        }

        private void StoreGetNamespacesSubresult(SubresultEventArgs<string> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " namespaces extracted.");
            if (e.Subresult.Count == 0)
            {
                mExtractCallGraphTypeNodesAsyncBlockerByNamespaces1.Set();
                return;
            }

            this.NumberOfThreadsStoringNamespaces += 1;
#if STORE_DEBUG
            Debug.WriteLine("Duplicates:");
#endif
            int i = 0;
            lock (this.Context)
            //using (ActualEntities context = GetContext(this.ModelPath.LocalPath))//this.Context;//new Model.ActualEntities();
            {
                var context = this.Context;
                foreach (var item in e.Subresult)
                {
                    this.State = item + " névtér tárolása";
                    if (context.Namespaces.Where(n => n.Name.Equals(item)).Count() == 0)
                    {
                        Namespace n = new Namespace() { Name = item };
                        context.Namespaces.AddObject(n);
                        try
                        {
                            context.SaveChanges();
                        }
                        catch (UpdateException ex)
                        {
                            if (context.Namespaces.Where(nn => nn.Name.Equals(item)).Count() == 0)
                                Trace.TraceError("Could not save " + n.Name + " namespace due to a constraint violation!");
                            else
                            {
                                context.Detach(n);
                                context.SaveChanges();
                            }
                        }
                        i++;
                    }
#if STORE_DEBUG
                    else
                        Debug.Write(item + " ");
#endif
                }
            }
            Debug.WriteLine(i.ToString() + " namespaces stored.");
            this.NumberOfThreadsStoringNamespaces -= 1;
        }

        private void StoreGetTypesSubresult(SubresultEventArgs<ExtendedType> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " types extracted.");
            if (e.Subresult.Count == 0)
            {
                mExtractCallGraphMemberNodesAsyncBlocker1.Set();
                return;
            }

            this.NumberOfThreadsStoringTypes += 1;
            mExtractCallGraphTypeNodesAsyncBlockerByModules3.WaitOne();
            mExtractCallGraphTypeNodesAsyncBlockerByNamespaces3.WaitOne();
            ;
#if STORE_DEBUG
            Debug.WriteLine("Duplicates:");
#endif
            int i = 0;
            lock (this.Context)
            //using (ActualEntities context = GetContext(this.ModelPath.LocalPath))//this.Context;//new Model.ActualEntities();
            {
                var context = this.Context;
                foreach (var item in e.Subresult)
                {
                    this.State = (item.OuterType ?? item.Type).ToString() + " típus tárolása";
                    ITypeDeclaration td = null;
                    bool resolved = item.Type.TryGetTypeDeclaration(out td);
                    if (resolved == true)
                    {
                        IModule iModule = item.Module;
                        //var queryA = context.Assemblies.Where(
                        //        a => a.Project.Name.Equals(this.ProjectName) && a.Name.Equals(td.Namespace));
                        //Debug.WriteLineIf(queryA.Count() != 1, "Adott nevű projektben adott asszembliből nem pontosan 1 található!");
                        //Assembly assembly = queryA.First();
                        var queryM = context.Modules.Where(
                            m => m.Name.Equals(iModule.Name)
                                && m.AssemblyName.Equals(iModule.Assembly.Name));
                        Debug.WriteLineIf(queryM.Count() != 1,
                            iModule.Name + " modulból nem pontosan 1 található!");
                        Module module = queryM.First();
                        var nsQuery = context.Namespaces.Where(n => n.Name.Equals(td.Namespace));
                        Namespace ns = null;
                        if (nsQuery.Count() > 0)
                            ns = nsQuery.First();
                        else if (item.OuterType != null)// if nsQuery.Count == 0, as if item.Type is nested, now it has a proper nested-namespace as Namespace
                        {
                            ITypeDeclaration outerTd = null;
                            if (item.OuterType.TryGetTypeDeclaration(out outerTd) == true)
                                ns = context.Namespaces.Where(n => n.Name.Equals(outerTd.Namespace)).First();
                        }
                        else
                            throw new AnalysisException("Can not store type " + item.Type.ToString() + " without any namespace!");

                        string tdPostfix = GetTypePostfix(td);
                        var tdQuery = context.Types.Where(
                            p => p.ModuleAssemblyName.Equals(iModule.Assembly.Name)
                                && p.ModuleName.Equals(iModule.Name)
                                && p.NamespaceName.Equals(ns.Name)
                                && p.Name.Equals(td.Name + tdPostfix));
                        //if (item.OuterType != null && tdQuery.Count() > 0)
                        //    Debugger.Break();
                        if (tdQuery.Count() == 0
                            || ((item.OuterType != null || item.IsNested == true) && tdQuery.Count() > 0))
                        {
                            Model.Type outerType = null;
                            string outerTdPostfix = "";
                            if (item.OuterType != null)// if item is a nested type
                            {
                                ITypeDeclaration outerTd = null;
                                if (item.OuterType.TryGetTypeDeclaration(out outerTd) == true)
                                {
                                    outerTdPostfix = GetTypePostfix(outerTd);
                                    var queryO = context.Types.Where(
                                        t => t.Name.Equals(outerTd.Name + outerTdPostfix)
                                            && t.NamespaceName.Equals(outerTd.Namespace)
                                            && t.ModuleName.Equals(iModule.Name)
                                            && t.ModuleAssemblyName.Equals(iModule.Assembly.Name));
                                    if (queryO.Count() > 0)// and its outer is already stored in the db
                                        outerType = queryO.First();
                                    else// or if it's not stored, then save it to resolve later, when it's possible
                                    {
                                        if (mUnresolvedTypes.Contains(item) == false)
                                            mUnresolvedTypes.Add(item);
                                    }
                                }
#if DEBUG
                                else
                                    MessageBox.Show(item.OuterType.ToString() + " outer type not resolved!");
#endif
                            }
                            else if (item.OuterType == null && item.IsNested == true)
                            {
                                if (mUnresolvedTypes.Contains(item) == false)
                                    mUnresolvedTypes.Add(item);
                                continue;
                            }

                            Model.Type type;
                            Model.Namespace nestedNamespace;
                            CreateType(context, item, td, module, ns, outerType, out type, out nestedNamespace);
                            if ((item.IsNested == true && outerType == null) == false)
                            {
                                if (nestedNamespace != null)
                                {//TODO check wether nestedNamespace is already exists, and review everywhere
                                    if (context.Namespaces.Where(
                                            pNS => pNS.Name.Equals(nestedNamespace.Name)).Count() == 0)
                                        context.Namespaces.AddObject(nestedNamespace);
                                    nestedNamespace.Types.Add(type);
                                }
                                else
                                    ns.Types.Add(type);

                                var existsQ = context.Types.Where(
                                        pT => pT.Name.Equals(type.Name)
                                            && pT.NamespaceName.Equals(type.NamespaceName)
                                            && pT.ModuleName.Equals(type.ModuleName));
                                if (existsQ.Count() == 0)
                                    context.Types.AddObject(type);
                                else
                                    context.Detach(type);

                                try
                                {
                                    context.SaveChanges();
                                }
                                catch (UpdateException ex)
                                {
#if DEBUG
                                    if ((ex.InnerException != null
                                        && ex.InnerException.Message == "Abort due to constraint violation\r\ncolumns Name, ModuleAssemblyName, ModuleName, NamespaceName are not unique"
                                        ) == false)
                                        ;
#endif
                                    if (context.Types.Where(
                                        ppT => ppT.Name.Equals(type.Name)
                                            && ppT.NamespaceName.Equals(type.NamespaceName)
                                            && ppT.ModuleName.Equals(type.ModuleName)).Count() == 0)
                                        Trace.TraceError("Could not save " + type.Name + " type due to a constraint violation!");
                                    else
                                    {
                                        context.Detach(type);
                                        context.SaveChanges();
                                    }
                                    //System.Diagnostics.Debug.WriteLine(ex.Message + " " + type.Name);
                                }
                            }
                            i++;
                        }
#if STORE_DEBUG
                        else
                            Debug.Write(td.Name + " ");
#endif
                    }
#if DEBUG
                    else
                        MessageBox.Show(item.Type.ToString() + " type not resolved!");
#endif
                }
            }
            Debug.WriteLine(i.ToString() + " types stored.");
            this.NumberOfThreadsStoringTypes -= 1;
        }

        /// <summary>
        /// Creates a non-nested, or a nested type.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="item">Extracted information about the type to create</param>
        /// <param name="td">TypeDeclaration of the type to create</param>
        /// <param name="module">Container module of the type to create</param>
        /// <param name="ns">Namespace of the type to create; if item.IsNested is true, it is not used</param>
        /// <param name="outerType">The outer type of the nested type to create, if it is nested, else null</param>
        /// <param name="type">The created type</param>
        /// <param name="properNamespace">The created namespace, if the type is nested, and the namespace
        /// was not existed yet</param>
        private static void CreateType(ActualEntities context, ExtendedType item, ITypeDeclaration td,
            Module module, Namespace ns, Model.Type outerType, out Model.Type type,
            out Model.Namespace properNamespace)
        {
            properNamespace = null;
            type = null;
            if ((item.IsNested == true && outerType == null) == false)
            // else continue as we need the name and namespace of the outer type to save
            // the nested one
            {

                properNamespace = context.GetNamespace(item.IsNested, outerType, ns, createIfNoExists: true);

                type =
                    new Model.Type()
                    {
                        ModuleAssemblyName = module.AssemblyName,
                        ModuleName = module.Name,
                        Name = td.Name + GetTypePostfix(td),
                        NamespaceName = item.IsNested == true ? properNamespace.Name : ns.Name,//TODO extract this
                        IsAbstract = td.Abstract,
                        IsInterface = td.Interface,
                        IsSealed = td.Sealed,
                        IsValueType = td.ValueType,
                        BeforeFieldInit = td.BeforeFieldInit,
                        RuntimeSpecialName = td.RuntimeSpecialName,
                        SpecialName = td.SpecialName,
                        Visibility = td.Visibility.ToString()
                    };
                //else
                //    type = tdQuery.First();
                if (outerType != null)
                {
                    type.Outer_TypeName = outerType.Name;
                    type.Outer_TypeNamespaceName = outerType.NamespaceName;
                    type.Outer_TypeModuleName = outerType.Outer_TypeModuleName;
                    type.Outer_TypeModuleAssemblyName = outerType.Outer_TypeModuleAssemblyName;
                    outerType.NestedType.Add(type);
                }
            }
        }

        private static string GetTypePostfix(ITypeDeclaration td)
        {
#if _NET_REFLECTOR
            return td.GenericArguments.Count == 0
                ? ""
                : "`" + td.GenericArguments.Count.ToString();
#elif MONO_CECIL
            return "";
#endif
        }

        private void StoreGetMembersSubresult(SubresultEventArgs<ExtendedMemberReference> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " members extracted.");
            if (e.Subresult.Count == 0)
            {
                mExtractCallGraphBlocker1.Set();
                return;
            }

            this.NumberOfThreadsStoringMembers += 1;
            mExtractCallGraphMemberNodesAsyncBlocker3.WaitOne();
#if STORE_DEBUG
            Debug.WriteLine("Duplicates:");
#endif
            int i = 0;
            lock (this.Context)
            //using (ActualEntities context = GetContext(this.ModelPath.LocalPath))//this.Context;//new Model.ActualEntities();
            {
                var context = this.Context;
                foreach (var item in e.Subresult)
                {
                    this.State = item.MemberReference.Name + " tag tárolása";
                    IMemberReference mr = item.MemberReference;
                    IModule iModule = item.Module;
                    var queryM = context.Modules.Where(
                        m => m.Name.Equals(iModule.Name) && m.AssemblyName.Equals(iModule.Assembly.Name));
                    Debug.WriteLineIf(queryM.Count() != 1,
                        iModule.Name + " modulból nem pontosan 1 található!");
                    Module module = queryM.First();
                    ITypeDeclaration declaringType = null;
                    if (mr.DeclaringType.TryGetTypeDeclaration(out declaringType) == true)
                    {
                        string memberName = mr.ToString();
                        string declaringTypePostfix = GetTypePostfix(declaringType);
                        string namespaceName;
                        //if (ExtendedType.GetIsNested(declaringType, item.OuterTypeDeclaration) == true)
                        //{
                        //    namespaceName =
                        //        item.OuterTypeDeclaration.Namespace + "."
                        //        + item.OuterTypeDeclaration.Name + GetTypePostfix(item.OuterTypeDeclaration);
                        //}
                        //else
                        namespaceName = declaringType.Namespace;
                        if (context.Members.Where(
                            mem => mem.TypeModuleAssemblyName.Equals(iModule.Assembly.Name)
                                && mem.TypeModuleName.Equals(item.Module.Name)
                                && mem.TypeName.Equals(declaringType.Name + declaringTypePostfix)
                                && mem.TypeNamespaceName.Equals(namespaceName)
                                && mem.Name.Equals(memberName)).Count() == 0)
                        {
                            Model.Type type = null;
                            try
                            {
                                type = context.Types.Where(
                                    t => t.Name.Equals(declaringType.Name + declaringTypePostfix)
                                        && t.ModuleName.Equals(item.Module.Name)
                                        && t.NamespaceName.Equals(namespaceName)
                                        && t.ModuleAssemblyName.Equals(iModule.Assembly.Name)).First();
                            }
                            catch (InvalidOperationException)
                            {
                                Trace.TraceError(
                                    "Could not find type entity with the data {" + declaringType.Name
                                    + "," + namespaceName + "," + item.Module.Name + "," + iModule.Assembly.Name
                                    + "} for member " + memberName + " !");
                            }
                            if (type != null)
                            {
                                Member member =
                                    new Member()
                                    {
                                        Name = memberName,
                                        Type = type,
                                        TypeName = type.Name,
                                        TypeNamespaceName = type.NamespaceName,
                                        TypeModuleName = type.ModuleName,
                                        TypeModuleAssemblyName = type.ModuleAssemblyName,
                                        MemberKind = mr.GetMemberKind().ToString()
                                    };
                                if (context.Members.Where(
                                    pM =>
                                        pM.Name.Equals(member.Name)
                                        && pM.TypeName.Equals(type.Name)
                                        && pM.TypeNamespaceName.Equals(type.NamespaceName)
                                        && pM.TypeModuleName.Equals(type.ModuleName)).Count() == 0)
                                {
                                    context.Members.AddObject(member);
                                }
                                try
                                {
                                    context.SaveChanges();
                                }
                                catch (UpdateException ex)
                                {
                                    var memberExistQ = context.Members.Where(
                                            pM =>
                                                pM.Name.Equals(member.Name)
                                                && pM.TypeName.Equals(type.Name)
                                                && pM.TypeNamespaceName.Equals(type.NamespaceName)
                                                && pM.TypeModuleName.Equals(type.ModuleName));
                                    if (memberExistQ.Count() == 0)
                                        Trace.TraceError("Could not save " + member.Name + " member due to a constraint violation!");
                                    else
                                    {
                                        context.Detach(member);
                                        context.SaveChanges();
                                    }
                                    //System.Diagnostics.Debug.WriteLine(ex.Message + " " + member.Name);
                                }
                            }
                            i++;
                        }
#if STORE_DEBUG
                        else
                            Debug.Write(memberName + " ");
#endif
                    }
#if DEBUG
                    else
                        MessageBox.Show(mr.DeclaringType.ToString() + " not resolved!");
#endif
                }
            }
            Debug.WriteLine(i.ToString() + " members stored.");
            this.NumberOfThreadsStoringMembers -= 1;
        }

        private void StoreCallGraphExtractionSubresult(SubresultEventArgs<CallGraphEdgeCollection> e)
        {
            Debug.WriteLine(e.Subresult.Count.ToString() + " callgraph edges extracted.");
            if (e.Subresult.Count == 0)
            {
                mParseFxCopReportToDBBlocker1.Set();
                return;
            }
            this.NumberOfThreadsStoringCallGraphEdges += 1;
            mExtractCallGraphBlocker3.WaitOne();
            int i = 0;
            lock (this.Context)
            //using (ActualEntities context = GetContext(this.ModelPath.LocalPath))//this.Context;//new Model.ActualEntities();
            {
                var context = this.Context;
                foreach (var item in e.Subresult)
                {
                    this.State = item.Caller.MemberReference.Name + " tagból kifutó élek tárolása";
                    // Store needed information in locals
                    IMemberReference caller = item.Caller.MemberReference;
                    string callerMemberName = caller.ToString();
                    ITypeDeclaration callerTypeDeclaration = null;
                    if (caller.DeclaringType.TryGetTypeDeclaration(out callerTypeDeclaration) == true)
                    {
                        if (item.Caller.Module == null)
                        {
                            Trace.TraceInformation("Calls from " + item.Caller.MemberReference.Name +
                                " could not be strored, as the container containerModule is not found before.");
                            break;
                        }
                        if (callerTypeDeclaration == null)
                            ;
                        string callerTypeName =
                            callerTypeDeclaration.Name + GetTypePostfix(callerTypeDeclaration);
                        string callerNamespaceName = callerTypeDeclaration.Namespace;
                        string callerModuleName = item.Caller.Module.Name;
                        string callerAssemblyName = item.Caller.Module.Assembly.Name;
                        // Find caller entities
                        var query = context.Members.Where(
                                m =>
                                    m.Name.Equals(callerMemberName)
                                    && m.TypeName.Equals(callerTypeName)
                                    && m.TypeNamespaceName.Equals(callerNamespaceName)
                                    && m.TypeModuleName.Equals(callerModuleName)
                                    && m.TypeModuleAssemblyName.Equals(callerAssemblyName)
                                    );
                        Debug.Assert(query.Count() == 1, "Pontosan egy entitás kellene létezzen az adott értékekkel!");
                        if (query.Count() == 0)
                        {
                            Trace.TraceError("{0}-->x callgraph edge could not be saved, as {0} from {1}, {2} not found!",
                                callerMemberName, callerNamespaceName, callerModuleName);
                            break;
                        }
                        Member callerMember = query.First();
                        Model.Type callerType = callerMember.Type;
                        Namespace callerNamespace = callerType.Namespace;
                        Module callerModule = callerType.Module;
                        Model.Assembly callerAssembly = callerModule.Assembly;

                        foreach (var callGraphEdge in item.Called)
                        {
                            StoreCallGraphEdge(context, callerMemberName, callerTypeName, callerNamespaceName,
                                callerModuleName, callerAssemblyName, callGraphEdge);
                            i++;
                        }
                    }
#if DEBUG
                    else
                        MessageBox.Show(caller.DeclaringType.ToString() + " caller type not resolved!");
#endif
                }
            }
            Debug.WriteLine(i.ToString() + " callgraph edges stored.");
            this.NumberOfThreadsStoringCallGraphEdges -= 1;
        }

        private static void StoreCallGraphEdge(ActualEntities context, string callerMemberName,
            string callerTypeName, string callerNamespaceName, string callerModuleName,
            string callerAssemblyName, CallGraphExtractor.CallGraphEdge callGraphEdge)
        {
            // Store needed information in locals
            IMemberReference callee = callGraphEdge.ExtendedMemberReference.MemberReference;
            string calleeMemberName = callee.ToString();
            ITypeDeclaration calleeTypeDeclaration = null;
            if (callee.DeclaringType.TryGetTypeDeclaration(out calleeTypeDeclaration) == true)
            {
                string calleeTypeName = calleeTypeDeclaration.Name + GetTypePostfix(calleeTypeDeclaration);
                string calleeNamespaceName = calleeTypeDeclaration.Namespace;
                if (callGraphEdge.ExtendedMemberReference.Module == null)
                {
                    Trace.TraceInformation("Calls to " + callGraphEdge.ExtendedMemberReference.MemberReference.Name +
                        " could not be strored, as the container containerModule is not found before.");
                    return;
                }
                string calleeModuleName = callGraphEdge.ExtendedMemberReference.Module.Name;
                string calleeAssemblyName = callGraphEdge.ExtendedMemberReference.Module.Assembly.Name;
                string callTypeS = callGraphEdge.CallType.ToString();
                // Find callee entities
                var query = context.Members.Where(
                        m =>
                            m.Name.Equals(calleeMemberName)
                            && m.TypeName.Equals(calleeTypeName)
                            && m.TypeNamespaceName.Equals(calleeNamespaceName)
                            && m.TypeModuleName.Equals(calleeModuleName)
                            && m.TypeModuleAssemblyName.Equals(calleeAssemblyName)
                            );
                Member calleeMember = null;
                if (query.Count() > 0)
                    calleeMember = query.First();
                else
                {
                    Trace.TraceError("Could not find callee member due to a bug! Member data is (Name={0}, TypeName={1}, Namespace={2}, Module={3})", calleeMemberName, calleeTypeName, calleeNamespaceName, calleeModuleName);
                    return;
                }
                Model.Type calleeType = calleeMember.Type;
                Namespace calleeNamespace = calleeType.Namespace;
                Module calleeModule = calleeType.Module;
                Model.Assembly calleeAssembly = calleeModule.Assembly;

                // Adding new entities
                if (callerAssemblyName.Equals(calleeAssemblyName) == false)
                    context.CallGraphEdge_AssemblyDependency.AddObjectSafe(
                        new Model.CallGraphEdge_AssemblyDependency()
                        {
                            Caller_AssemblyName = callerAssemblyName,
                            Callee_AssemblyName = calleeAssemblyName
                        },
                        callTypeS);
                if (callerModuleName.Equals(calleeModule) == false
                    && callerAssemblyName.Equals(calleeAssemblyName) == false)
                    context.CallGraphEdge_ModuleDependency.AddObjectSafe(
                        new Model.CallGraphEdge_ModuleDependency()
                        {
                            Caller_ModuleAssemblyName = callerAssemblyName,
                            Callee_ModuleAssemblyName = calleeAssemblyName,
                            Caller_ModuleName = callerModuleName,
                            Callee_ModuleName = calleeModuleName
                        },
                        callTypeS);
                if (callerNamespaceName.Equals(calleeNamespace) == false)
                    context.CallGraphEdge_NamespaceDependency.AddObjectSafe(
                        new Model.CallGraphEdge_NamespaceDependency()
                        {
                            Caller_NamespaceName = callerNamespaceName,
                            Callee_NamespaceName = calleeNamespaceName
                        },
                        callTypeS);
                if (callerTypeName.Equals(calleeTypeName) == false
                    && callerNamespaceName.Equals(calleeNamespace) == false
                    && callerModuleName.Equals(calleeModule) == false
                    && callerAssemblyName.Equals(calleeAssemblyName) == false)
                    context.CallGraphEdge_TypeDependency.AddObjectSafe(
                        new Model.CallGraphEdge_TypeDependency()
                        {
                            Caller_TypeModuleAssemblyName = callerAssemblyName,
                            Callee_TypeModuleAssemblyName = calleeAssemblyName,
                            Caller_TypeModuleName = callerModuleName,
                            Callee_TypeModuleName = calleeModuleName,
                            Caller_TypeNamespaceName = callerNamespaceName,
                            Callee_TypeNamespaceName = calleeNamespaceName,
                            Caller_TypeName = callerTypeName,
                            Callee_TypeName = calleeTypeName
                        },
                        callTypeS);
                context.CallGraphEdge_MemberDependency.AddObjectSafe(
                    new Model.CallGraphEdge_MemberDependency()
                    {
                        Caller_MemberTypeModuleAssemblyName = callerAssemblyName,
                        Callee_MemberTypeModuleAssemblyName = calleeAssemblyName,
                        Caller_MemberTypeModuleName = callerModuleName,
                        Callee_MemberTypeModuleName = calleeModuleName,
                        Caller_MemberTypeNamespaceName = callerNamespaceName,
                        Callee_MemberTypeNamespaceName = calleeNamespaceName,
                        Caller_MemberTypeName = callerTypeName,
                        Callee_MemberTypeName = calleeTypeName,
                        Caller_MemberName = callerMemberName,
                        Callee_MemberName = calleeMemberName
                    },
                    callTypeS);
            }
#if DEBUG
            else
                MessageBox.Show(callee.DeclaringType.ToString() + " callee type not resolved!");
#endif
        }

        #endregion Store to DB

        #endregion Methods

        #region EventHandlers

        void HandlerProgressChanged(ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage < 0)
            {
                this.IsProgressIndeterminate = true;
                this.Progress = 0;
            }
            else
            {
                this.IsProgressIndeterminate = false;
                this.Progress = e.ProgressPercentage;
            }
        }

        #region init

        void init_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
            string message = e.UserState as string;
            if (message != null)
                DispatchService.Dispatch(() => this.Output.Add(message));
        }

        #endregion init

        #region mAnalysisWorker

        /// <summary>
        /// DefaultCollaboration 4
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void mAnalysisWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            DispatchService.Dispatch(() =>
            {
                if (CopyFiles(e.Argument as List<AssemblyViewModel>) == false)
                {
                    this.HasError = true;
                    return;
                }
            });

            if (CreateDB() == false) // Create DB
            {
                this.HasError = true;
                return;
            }
            this.IsProgressIndeterminate = false;
            if (this.OnlyRewriteFxCopReport == false)
            {
                mExtractor.AssemblyPaths.Clear();
                foreach (var file in this.Files)
                {
                    try
                    {
                        mExtractor.AssemblyPaths.Add(new Uri(file.FilePath, UriKind.Absolute));
                    }
                    catch (UriFormatException ex)
                    {
                        System.Windows.MessageBox.Show(ex.Message);
                        this.HasError = true;
                        return;
                    }
                }
                ExtractCallGraphAssemblyNodesAsync(); //Start extraction procedure
            }
            else
            {
                this.Context.DeleteFxCopReport();
                mParseFxCopReportToDBBlocker1.Set();
                mExtractCallGraphBlocker3.Set();
                mParseFxCopReportToDBBlocker3.Set();
                mExtractor_ExtractionDone(null, null);
            }
        }

        void mAnalysisWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            throw new NotImplementedException();
        }

        void mAnalysisWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                this.HasError = true;
                System.Windows.MessageBox.Show(e.Error.Message);
                Trace.TraceError("{0}\n{1}", e.Error.Message, e.Error.StackTrace);
            }
        }

        #endregion mAnalysisWorker

        #region mCallGraphExtractor

        #region Assemblies

        void mExtractor_GetAssembliesSubresultExtracted(object sender, SubresultEventArgs<IAssembly> e)
        {
            mGetAssembliesSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetAssembliesSubresultHandler_CallbackMethod),
                null);
        }

        void mGetAssembliesSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetAssembliesSubresultHandler caller =
                (GetAssembliesSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
        }

        void mExtractor_GetAssembliesProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        void mExtractor_GetAssembliesDone(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null || e.Cancelled == true)
            {
                MessageBox.Show(e.Error.Message);
                Trace.TraceError("{0}\n{1}", e.Error.Message, e.Error.StackTrace);
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("...kész."));
            mExtractCallGraphModuleNodesAsyncBlocker2.Set();
            ExtractCallGraphModuleNodesAsync();
            ExtractCallGraphNamespaceNodesAsync();
        }

        #endregion Assemblies

        #region Modules

        void mExtractor_GetModulesSubresultExtracted(object sender, SubresultEventArgs<IModule> e)
        {
            mGetModulesSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetModulesSubresultHandler_CallbackMethod),
                null);
        }

        void mGetModulesSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetModulesSubresultHandler caller =
                (GetModulesSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
        }

        void mExtractor_GetModulesProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        void mExtractor_GetModulesDone(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null || e.Cancelled == true)
            {
                MessageBox.Show(e.Error.Message);
                Trace.TraceError("{0}\n{1}", e.Error.Message, e.Error.StackTrace);
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Modulok kinyerése kész!"));
            mExtractCallGraphTypeNodesAsyncBlockerByModules2.Set();
        }

        #endregion Modules

        #region Namespaces

        void mExtractor_GetNamespacesSubresultExtracted(object sender, SubresultEventArgs<string> e)
        {
            mGetNamespacesSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetNamespacesSubresultHandler_CallbackMethod),
                null);
        }

        void mGetNamespacesSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetNamespacesSubresultHandler caller =
                (GetNamespacesSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
        }

        void mExtractor_GetNamespacesProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        void mExtractor_GetNamespacesDone(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null || e.Cancelled == true)
            {
                MessageBox.Show(e.Error.Message);
                Trace.TraceError("{0}\n{1}", e.Error.Message, e.Error.StackTrace);
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Névterek kinyerése kész!"));
            mExtractCallGraphTypeNodesAsyncBlockerByNamespaces2.Set();
            ExtractCallGraphTypeNodesAsync();
        }

        #endregion Namespaces

        #region Types

        void mExtractor_GetTypesSubresultExtracted(object sender, SubresultEventArgs<ExtendedType> e)
        {
            mGetTypesSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetTypesSubresultHandler_CallbackMethod),
                null);
        }

        void mGetTypesSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetTypesSubresultHandler caller =
                (GetTypesSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
        }

        void mExtractor_GetTypesProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        void mExtractor_GetTypesDone(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null || e.Cancelled == true)
            {
                MessageBox.Show(e.Error.Message);
                Trace.TraceError("{0}\n{1}", e.Error.Message, e.Error.StackTrace);
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Típusok kinyerése kész!"));
            mExtractCallGraphMemberNodesAsyncBlocker2.Set();
            ExtractCallGraphMemberNodesAsync();
            mExtractCallGraphMemberNodesAsyncBlocker3.WaitOne();
            ResolveNestedTypeAssociations();
            DispatchService.Dispatch(() => this.Output.Add("Hiányzó Type-NestedType asszociációk létrehozása kész!"));
        }

        #endregion Types

        #region Members

        void mExtractor_GetMembersSubresultExtracted(object sender, SubresultEventArgs<ExtendedMemberReference> e)
        {
            mGetMembersSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mGetMembersSubresultHandler_CallbackMethod),
                null);
        }

        void mGetMembersSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            GetMembersSubresultHandler caller =
                (GetMembersSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
        }

        void mExtractor_GetMembersProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        void mExtractor_GetMembersDone(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null || e.Cancelled == true)
            {
                MessageBox.Show(e.Error.Message);
                Trace.TraceError("{0}\n{1}", e.Error.Message, e.Error.StackTrace);
                this.HasError = true;
                return;
            }
            DispatchService.Dispatch(() => this.Output.Add("Tagok kinyerése kész!"));
            mExtractCallGraphBlocker2.Set();
            ExtractCallGraph();
        }

        #endregion Members

        #region Calls

        void mExtractor_SubresultExtracted(object sender, SubresultEventArgs<CallGraphEdgeCollection> e)
        {
            mCallGraphExtractionSubresultHandler.BeginInvoke(
                e,
                new AsyncCallback(mCallGraphExtractionSubresultHandler_CallbackMethod),
                null);
        }

        void mCallGraphExtractionSubresultHandler_CallbackMethod(IAsyncResult result)
        {
            CallGraphExtractionSubresultHandler caller =
                (CallGraphExtractionSubresultHandler)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
        }

        void mExtractor_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        void mExtractor_ExtractionDone(object sender, RunWorkerCompletedEventArgs e)
        {
            if (this.OnlyRewriteFxCopReport == false)
            {
                if (e.Error != null || e.Cancelled == true)
                {
                    MessageBox.Show(e.Error.Message);
                    Trace.TraceError("{0}\n{1}", e.Error.Message, e.Error.StackTrace);
                    this.HasError = true;
                    return;
                }
                DispatchService.Dispatch(() => this.Output.Add("Hívási gráf kinyerése kész!"));
            }

            if (ProcessFxCopReport() == false)
                return;

            MessageBox.Show("!");
            this.IsProgressIndeterminate = false;
            this.Progress = 0;
            DispatchService.Dispatch(() => DeleteFiles(this.Files.ToList()));
        }

        private bool ProcessFxCopReport()
        {
            RunFxCopAnalysis();
            mParseFxCopReportToDBBlocker1.WaitOne();
            mExtractCallGraphBlocker3.WaitOne();
            mParseFxCopReportToDBBlocker3.WaitOne();
            try
            {
                using (ActualEntities context = new ActualEntities(this.Context.Connection.ConnectionString))
                {
                    this.State = "FxCop riport mentése az adatbázisba...";
                    var adapter = new Adapter();
                    adapter.ParsingProgressChanged += new EventHandler<ProgressChangedEventArgs>(adapter_ParsingProgressChanged);
                    adapter.ParseToDB(this.FxCopOutputPath, context);
                }
            }
            catch (FileNotFoundException ex)
            {
                this.HasError = true;
                DispatchService.Dispatch(() => this.Output.Add(ex.Message));
                return false;
            }
            DispatchService.Dispatch(() => this.Output.Add("FxCop riport feldolgozása kész!"));
            return true;
        }

        #endregion Calls

        #region FxCop report

        void adapter_ParsingProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            HandlerProgressChanged(e);
        }

        #endregion FxCop report

        void mExtractor_Informating(object sender, InformationEventArgs e)
        {
            DispatchService.Dispatch(() => this.Output.Add(e.Information));
        }

        void mExtractor_StateChanged(object sender, InformationEventArgs e)
        {
            this.State = e.Information;
        }

        #endregion mCallGraphExtractor

        #endregion EventHandlers

        #region IDataErrorInfo Members

        public string Error
        {
            get { throw new NotImplementedException(); }
        }

        public string this[string property]
        {
            get
            {
                string msg = null;
                switch (property)
                {
                    case "FxCop10Path":
                        if (File.Exists(this.FxCop10Path.LocalPath) == false)
                            msg = "A " + this.FxCop10Path.AbsolutePath
                                + " fájl nem található! Használja a Tallózás funkciót!";
                        break;
                    case "FxCopRulesPath":
                        if (Directory.Exists(this.FxCopRulesPath.LocalPath) == false)
                            msg = "A " + this.FxCopRulesPath
                                + " mappa nem található! Használja a Tallózás funkciót!";
                        break;
                    case "VisualStudioRulesPath":
                        if (this.VisualStudioRulesPath != null
                            && Directory.Exists(this.VisualStudioRulesPath.LocalPath) == false)
                            msg = "A " + this.VisualStudioRulesPath
                                + " mappa nem található! Használja a Tallózás funkciót!";
                        break;
                    default:
                        throw new ArgumentException(
                            "Unrecognized property: " + property);
                }
                return msg;
            }
        }

        #endregion
    }
}
